package middleware

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"time"
	ext "vrcm/src/vrcm/envconfig"

	"github.com/gin-gonic/gin"
)

var lastRequestPath string
var lastRequestMethod string

// NoCache is a middleware function that appends headers
// to prevent the client from caching the HTTP response.
func NoCache(c *gin.Context) {
	c.Header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value")
	c.Header("Expires", "Thu, 01 Jan 1970 00:00:00 GMT")
	c.Header("Last-Modified", time.Now().UTC().Format(http.TimeFormat))
	//c.Header("Content-Length", "-1")
	c.Next()
}

// Options is a middleware function that appends headers
// for options requests and aborts then exits the middleware
// chain and ends the request.
func Options(c *gin.Context) {
	//if c.Request.Method == "OPTIONS" {
	//	c.AbortWithStatus(http.StatusNoContent)
	//} else {
	//
	//	c.Header("Access-Control-Allow-Origin", "*")
	//	c.Header("Access-Control-Allow-Methods", "GET,POST,PUT,PATCH,DELETE,OPTIONS")
	//	c.Header("Access-Control-Allow-Headers", "authorization, origin, content-type, accept")
	//	c.Header("Allow", "HEAD,GET,POST,PUT,PATCH,DELETE,OPTIONS")
	//	c.Header("Content-Type", "application/json")
	//	//c.AbortWithStatus(200)
	//}
	//c.Next()

	method := c.Request.Method
	keys := "x-token, X-Token, Authorization, content-type, authorization"
	for k, _ := range c.Request.Header {
		if keys != "" {
			keys = keys + ", " + k
		} else {
			keys += k
		}
	}
	c.Header("Access-Control-Allow-Origin", "*")
	c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin"))
	c.Header("Access-Control-Allow-Methods", "PGET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS")
	c.Header("Access-Control-Allow-Headers", keys)
	c.Header("Access-Control-Allow-Credentials", "true")
	c.Header("Access-Control-Max-Age", "86400")
	// 放行所有OPTIONS方法
	if method == "OPTIONS" {
		c.AbortWithStatus(http.StatusNoContent)
		return
	}
	c.Next()

}

// Secure is a middleware function that appends security
// and resource access headers.
func Secure(c *gin.Context) {
	c.Header("Access-Control-Allow-Origin", "*")
	//c.Header("X-Frame-Options", "DENY")
	c.Header("X-Content-Type-Options", "nosniff")
	c.Header("X-XSS-Protection", "1; mode=block")
	if c.Request.TLS != nil {
		c.Header("Strict-Transport-Security", "max-age=31536000")
	}

	// Also consider adding Content-Security-Policy headers
	// c.Header("Content-Security-Policy", "script-src 'self' https://cdnjs.cloudflare.com")
}

//
//func PreventDuplicateClicks(c *gin.Context) {
//	if c.Request.Method == lastRequestMethod && c.FullPath() == lastRequestPath {
//		lastRequestMethod = ""
//		lastRequestPath = ""
//		c.JSON(http.StatusBadRequest, gin.H{"error": "Duplicate click"})
//		c.Abort()
//		return
//	}
//	lastRequestMethod = c.Request.Method
//	lastRequestPath = c.FullPath()
//
//	c.Next()
//}

func Auth() gin.HandlerFunc {
	return func(c *gin.Context) {
		b := CheckToken(c)
		if !b {
			c.JSON(http.StatusUnauthorized, gin.H{"message": "Unauthorized", "code": 502})
			c.Abort()
			return
		}
		c.Next()
	}
}

var IgnoreUrlMap = map[string]struct{}{
	"get-schedule-flow-statistics": {},
	"get-live-state":               {},
	"get-personalization":          {},
	"get-draw":                     {},
	"get-likes-num":                {},
	"get-user-award-info":          {},
	"record-file-callback":         {},
}

func CheckToken(c *gin.Context) bool {

	token := c.Query("permissionToken")
	tenantId := c.Query("permissionTenantId")
	useId := c.Query("permissionUserId")
	ip := c.Query("permissionIp")
	appType := c.Query("permissionAppType")
	umsAddress := ext.ExtConfig.ServiceConfig.VruServiceUrl
	flag := false
	for k, _ := range IgnoreUrlMap {
		if strings.Contains(c.Request.URL.Path, k) {
			flag = true
			break
		}
	}
	if flag {
		return true
	}
	_, ok := IgnoreUrlMap[c.Request.URL.Path]
	if ok {
		return true
	}

	if token == "vsnb" {
		return true
	}

	body1, err := ioutil.ReadAll(c.Request.Body)
	if err != nil {
		return false
	}
	c.Request.Body = io.NopCloser(bytes.NewBuffer(body1))

	response1 := ResponseResult1{}
	err = json.Unmarshal(body1, &response1)
	if err != nil {
		log.Println(err.Error())
		//return false
	}
	//log.Println("租户信息：", response1.TenantId, tenantId)
	if len(response1.TenantId) > 0 && response1.TenantId != tenantId && response1.TenantId != "vsdefault" {
		return false
	}
	//fmt.Println("相等:", response1, tenantId)

	reqUrl := fmt.Sprintf(`%s/api/v2/permission?token=%s&tenantId=%s&userId=%d&ip=%s&appType=%s`, umsAddress, token, tenantId, useId, ip, appType)
	log.Println("ums assets req url", reqUrl)
	req, err := http.NewRequest("POST", reqUrl, nil)
	if err != nil {
		log.Println(err.Error())
		return false
	}
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Println("url is :" + reqUrl)
		//logs.Error(err.Error())
		return false
	}

	if res.StatusCode != 200 {
		log.Println("Query for UMS interface failed, return status code not 200.")
		return false
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Println(err.Error())
		//logs.Error(err.Error())
		return false
	}
	response := ResponseResult{}
	err = json.Unmarshal(body, &response)
	if err != nil {
		log.Println(err.Error())
		return false
	}

	if response.Code != 200 {
		log.Println(err.Error())
		return false
	}

	return true
}

type ResponseResult struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data"`
}

type ResponseResult1 struct {
	TenantId string `json:"tenant_id" comment:"租户id"`
}
